import time
import random
import sys
import building
import faction
import map
import net
import player
import pyglet
from pyglet.gl import *
import sprite
import thing
import unit
import window as windoe # avoid naming conflict
import tactical


state = None
local_player = None
window = None
network = None


def init(player_name, f, host, port, latency, packet_loss, client):

	global window
	window = windoe.Window()

	global state
	state = GameState()

	global local_player
	local_player = sprite.GroupSingle(player.Player(random.randint(-sys.maxint-1, sys.maxint), player_name, faction.get(f), None, None)) # "unique" id

	global network
	if client:
		network = net.MechazoidClient(host, port, latency, packet_loss)
	else:
		network = net.MechazoidServer(host, port, latency, packet_loss)
	state.request_player_create(local_player.id, local_player.name, local_player.faction.id)


class GameState(pyglet.event.EventDispatcher):

	def __init__(self):
		self.time = 0
		self.map = map.Map('hunted.map')
		self.tactical_handler = tactical.TacticalController(
			self.map, (0, 0, window.width, window.height))
		self.push_handlers(self.tactical_handler)
		self.selection_handler = tactical.SelectionHandler()
		self.push_handlers(self.selection_handler)
		self.building_handler = tactical.BuildingHandler()
		self.push_handlers(self.building_handler)
		self.talk_handler = TalkHandler()
		self.push_handlers(self.talk_handler)
		window.push_handlers(self)

		pyglet.clock.schedule_interval(self.update, 1.0/60)
	
	def update(self, dt):
		self.time += dt
		self.dispatch_event('on_update', dt)

	def request_player_create(self, player_id, name, faction_id):
		self.dispatch_event('on_request_player_create', player_id, name, faction_id)

	def player_create(self, player_id, name, faction, mineral, gas):
		player.Player(player_id, name, faction, mineral, gas)
		self.dispatch_event('on_player_create', player_id, name, faction, mineral, gas)

	def player_state_update(self, player_id, name, faction, mineral, gas):
		self.dispatch_event('on_player_state_update', player_id, name, faction, mineral, gas)

	def player_kill(self, player_id):
		self.dispatch_event('on_player_kill', player_id)

	def request_unit_create(self, class_name, owner, health, location, destination):
		self.dispatch_event('on_request_unit_create', class_name, owner, health, location, destination)

	def unit_create(self, unit_id, class_name, owner, health, location, target, destination):
		if unit_id is None:
			unit_id = thing.next_id()
		unit_class = getattr(unit, class_name)
		if owner is not None and unit_class.mineral_cost <= owner.mineral and unit_class.gas_cost <= owner.gas:
			owner.mineral -= unit_class.mineral_cost
			owner.gas -= unit_class.gas_cost
			unit_class(unit_id, owner, health, location, target, destination)
			self.dispatch_event('on_unit_create', class_name, owner, health, location, target, destination)

	def unit_state_update(self, unit_id, owner, health, location, size, target, destination):
		self.dispatch_event('on_unit_state_update', unit_id, owner, health, location, size, target, destination)

	def request_unit_move(self, unit_id, destination):
		self.dispatch_event('on_request_unit_move', unit_id, destination)

	def unit_move(self, unit_id, destination):
		self.dispatch_event('on_unit_move', unit_id, destination)

	def unit_kill(self, unit_id):
		self.dispatch_event('on_unit_kill', unit_id)

	def request_building_create(self, class_name, owner_id, health, location):
		self.dispatch_event('on_request_building_create', class_name, owner_id, health, location)

	def building_create(self, building_id, class_name, owner, health, location, size):
		if building_id is None:
			building_id = thing.next_id()
		building_class = getattr(building, class_name)
		if owner is not None and building_class.mineral_cost <= owner.mineral and building_class.gas_cost <= owner.gas:
			owner.mineral -= building_class.mineral_cost
			owner.gas -= building_class.gas_cost
			building_class(building_id, owner, health, location, size)
			self.dispatch_event('on_building_create')

	def building_state_update(self, building_id, owner, health, location, size, target):
		self.dispatch_event('on_building_state_update', building_id, owner, health, location, size, target)

	def building_kill(self, building_id):
		self.dispatch_event('on_building_kill', building_id)

	def request_talk(self, msg):
		self.dispatch_event('on_request_talk', msg)

	def talk(self, msg):
		self.dispatch_event('on_talk', msg)

	# Relay many window events to our child handlers

	def on_draw(self, *args):
		self.relay_event('on_draw', *args)

	def on_key_press(self, *args):
		self.relay_event('on_key_press', *args)
	
	def on_key_release(self, *args):
		self.relay_event('on_key_release', *args)
	
	def on_text(self, *args):
		self.relay_event('on_text', *args)
	
	def on_mouse_motion(self, *args):
		self.relay_event('on_mouse_motion', *args)

	def on_mouse_drag(self, *args):
		self.relay_event('on_mouse_drag', *args)

	def on_mouse_press(self, *args):
		self.relay_event('on_mouse_press', *args)

	def on_mouse_release(self, *args):
		self.relay_event('on_mouse_release', *args)

	def on_mouse_scroll(self, *args):
		self.relay_event('on_mouse_scroll', *args)

	def relay_event(self, event_type, *args):
		'''Similar to dispatch_event, only it does not call the event
		handler on the dispatcher itself, which is not deisired for relaying.

		:Parameters:
			`event_type` : str
				Name of the event.
			`args` : sequence
				Arguments to pass to the event handler.

		'''
		assert event_type in self.event_types

		# Search handler stack for matching event handlers
		for frame in list(self._event_stack):
			handler = frame.get(event_type, None)
			if handler:
				try:
					if handler(*args):
						return
				except TypeError:
					self._raise_dispatch_exception(event_type, args, handler)

GameState.register_event_type('on_key_press')
GameState.register_event_type('on_key_release')
GameState.register_event_type('on_text')
GameState.register_event_type('on_mouse_motion')
GameState.register_event_type('on_mouse_drag')
GameState.register_event_type('on_mouse_press')
GameState.register_event_type('on_mouse_release')
GameState.register_event_type('on_mouse_scroll')
GameState.register_event_type('on_draw')
GameState.register_event_type('on_update')
GameState.register_event_type('on_request_player_create')
GameState.register_event_type('on_player_create')
GameState.register_event_type('on_player_state_update')
GameState.register_event_type('on_player_kill')
GameState.register_event_type('on_request_unit_create')
GameState.register_event_type('on_unit_create')
GameState.register_event_type('on_unit_state_update')
GameState.register_event_type('on_request_unit_move')
GameState.register_event_type('on_unit_move')
GameState.register_event_type('on_unit_kill')
GameState.register_event_type('on_request_building_create')
GameState.register_event_type('on_building_create')
GameState.register_event_type('on_building_state_update')
GameState.register_event_type('on_building_kill')
GameState.register_event_type('on_request_talk')
GameState.register_event_type('on_talk')
GameState.register_event_type('on_map_press')
GameState.register_event_type('on_map_release')
GameState.register_event_type('on_map_drag')
GameState.register_event_type('on_map_click')
GameState.register_event_type('on_draw_tactical_iso')
GameState.register_event_type('on_draw_tactical_hud')


class TalkHandler:

	PREFIX = '> '

	def __init__(self):
		self.expiration = None
		self.active = False
		self.label = None

	def on_draw_tactical_hud(self):
		if self.active or (self.expiration is not None or self.expiration > time.time()):
			self.label.draw()

	def activate(self):
		self.label = pyglet.text.Label(self.PREFIX, 
			font_name=local_player.faction.font_name, 
			font_size=local_player.faction.font_size, x=10, y=10)
		self.expiration = None
		self.active = True

	def on_text(self, text):
		if self.active and self.expiration is None:
			self.label.text += text
			return pyglet.event.EVENT_HANDLED

	def on_key_press(self, symbol, modifiers):
		if self.active and symbol in (pyglet.window.key.ENTER, pyglet.window.key.ESCAPE):
			# chat done
			txt = self.label.text[len(self.PREFIX):].strip()
			if symbol == pyglet.window.key.ENTER and txt:
				msg = local_player.name + ': ' + txt
				state.request_talk(msg)
			self.active = False
			return pyglet.event.EVENT_HANDLED
		if not self.active and symbol == pyglet.window.key.ENTER:
			self.activate()
			return pyglet.event.EVENT_HANDLED
		if self.active:
			# Eat all key presses when active
			return pyglet.event.EVENT_HANDLED

	def on_talk(self, msg):
		if self.label is None:
			self.activate()
		if msg != self.label.text:
			self.label.text = msg
			self.expiration = time.time() + 5 # seconds
			self.active = False

	def on_player_create(self, player_id, name, faction, mineral, gas):
		self.on_talk('%s joined the game' % name)

